package testalgorithm;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Random;

/**
 *
 * @author haoliang.donghl
 */
public class GenerateInput {

    public static int NUM_APP = 100;
    public static int NUM_MACHINE = 3;
    public static float CPU_UP_BOUND = 0.6f;
    public static float[][] matrixState;
    public static int[][] matrixIn;
    public static int[] vectorAppSize;
    public static float[] vectorAppCPU;
    public static float[] vectorMachineCPU;
    public static String dicname;

    public static void createFile(String dictionary, String filename) {
        try {
            File file;
            file = new File(dictionary);
            if (!file.exists()) {
                file.mkdirs();
            }

            file = new File(filename);
            if (!file.exists()) {
                file.createNewFile();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static int valueToId(float value) {
        for (int i = 0; i < NUM_MACHINE; i++) {
            if (value < vectorMachineCPU[i]) {
                return i;
            }
        }
        return NUM_MACHINE - 1;
    }

    private static boolean checkConstraint(int[][] matrix) {
        int runningNum;
        float perCPU;
        for (int i = 0; i < NUM_APP; i++) {
            runningNum = 0;
            for (int j = 0; j < NUM_MACHINE; j++) {
                if (matrix[i][j] == 2) {
                    runningNum++;
                }
            }

            if (runningNum == 0) {
                perCPU = 0;
            } else {
                perCPU = ((float) vectorAppCPU[i]) / runningNum;
            }

            for (int j = 0; j < NUM_MACHINE; j++) {
                if (matrix[i][j] == 2) {
                    matrixState[i][j] = perCPU;
                } else {
                    matrixState[i][j] = 0;
                }
            }
        }

        for (int j = 0; j < NUM_MACHINE; j++) {
            vectorMachineCPU[j] = 0;
            for (int i = 0; i < NUM_APP; i++) {
                vectorMachineCPU[j] += matrixState[i][j];
            }
        }

        for (int j = 0; j < NUM_MACHINE; j++) {
            if (vectorMachineCPU[j] > CPU_UP_BOUND ||
                    vectorMachineCPU[j] < 0) {
                return false;
            }
        }

        return true;
    }

    public static void printAssign(int[][] matrix) {
        if (dicname != null) {
            try {
                PrintWriter out = new PrintWriter(
                        new BufferedWriter(new FileWriter(dicname + "\\in.txt")));
                for (int i = 0; i < NUM_APP; i++) {
                    for (int j = 0; j < NUM_MACHINE; j++) {
                        out.print(matrix[i][j]);
                    }
                    out.println();
                }
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void printAppNeeds() {
        if (dicname != null) {
            try {
                PrintWriter out = new PrintWriter(
                        new BufferedWriter(new FileWriter(dicname + "\\cpu.txt")));
                for (int i = 0; i < NUM_APP; i++) {
                    out.println(vectorAppCPU[i]);
                }
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void printInfo() {
        if (dicname != null) {
            try {
                PrintWriter out = new PrintWriter(
                        new BufferedWriter(new FileWriter(dicname + "\\info.txt")));
                out.println(NUM_APP);
                out.println(NUM_MACHINE);
                out.println(CPU_UP_BOUND);
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void printAppSize() {
        if (dicname != null) {
            try {
                PrintWriter out = new PrintWriter(
                        new BufferedWriter(new FileWriter(dicname + "\\size.txt")));
                for (int i = 0; i < NUM_APP; i++) {
                    out.println(vectorAppSize[i]);
                }
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void printMachineCPU() {
        /*
        for (int i = 0; i < NUM_MACHINE; i++) {
            System.out.print("MACHINE");
            System.out.print("");
            System.out.print(i + 1);
            System.out.print(": ");
            System.out.println(vectorMachineCPU[i]);
        }
        */
    }

    public static void main(String[] args) {
        matrixIn = new int[NUM_APP][NUM_MACHINE];
        matrixState = new float[NUM_APP][NUM_MACHINE];
        vectorAppSize = new int[NUM_APP];
        vectorAppCPU = new float[NUM_APP];
        vectorMachineCPU = new float[NUM_MACHINE];

        vectorMachineCPU[0] = 0.75f;
        vectorMachineCPU[1] = 0.1f;
        vectorMachineCPU[2] = 0.05f;

        float averageCPU = 0;
        for (int i = 0; i < vectorMachineCPU.length; i++){
            averageCPU += vectorMachineCPU[i];
        }
        averageCPU /= NUM_APP;

        Random random = new Random();
        for (int i = 0; i < NUM_APP; i++) {
            vectorAppCPU[i] = (float) (Math.abs(random.nextGaussian() + 1.0f) * averageCPU);
            vectorAppSize[i] = random.nextInt(20) + 1;
        }

        //vectorMachineCPU[3] = 0.4f;
        //vectorMachineCPU[4] = 0.5f;
        float sumCPU = 0;
        float value;
        for (int i = 0; i < NUM_MACHINE; i++) {
            sumCPU += vectorMachineCPU[i];
        }
        vectorMachineCPU[0] = vectorMachineCPU[0] / sumCPU;
        for (int i = 1; i < NUM_MACHINE; i++) {
            vectorMachineCPU[i] = vectorMachineCPU[i - 1] + vectorMachineCPU[i] / sumCPU;
        }
        for (int i = 0; i < NUM_APP; i++) {
            for (int j = 0; j < NUM_MACHINE; j++) {
                matrixIn[i][j] = 0;
            }
        }
        for (int k = 0; k < 3; k++) {
            for (int i = 0; i < NUM_APP; i++) {
                value = random.nextFloat();
                matrixIn[i][valueToId(value)] = 2;
            }
        }
        for (int k = 0; k < 1; k++) {
            for (int i = 0; i < NUM_APP; i++) {
                value = random.nextFloat();
                if (matrixIn[i][valueToId(value)] != 2)
                    matrixIn[i][valueToId(value)] = 1;
            }
        }


        if (args.length > 0) {
            dicname = args[0];
        } else {
            dicname = "default";
        }
        if (dicname != null){
            createFile(dicname, dicname + "\\cpu.txt");
            createFile(dicname, dicname + "\\size.txt");
            createFile(dicname, dicname + "\\in.txt");
            createFile(dicname, dicname + "\\info.txt");
        }
        checkConstraint(matrixIn);
        printAppNeeds();
        printAssign(matrixIn);
        printAppSize();
        printMachineCPU();
        printInfo();
    }
}
